﻿using System;
using System.Data;
using System.IO;
using System.Text;
using System.Threading;
using System.Web.Services;
using System.Web.Services.Protocols;
using HelpdeskServices.Properties;
using HelpdeskServices.CrmWebReference;
using HelpdeskServices.KmsWebReference;

/// <summary>
/// ///
/// ///    Notes exceptions, exclusions, or any other funny's you need 
/// ///    to know about CombinedSearch
/// ///
/// Liquid Thought
/// Created by:Rihan
/// 
/// Creates a combined datatable
///     Fetch records from CRM and put them in a table
///     Fetch records from KMS and put them in a table
///  
///     Combine the table
/// 
///     
/// </summary>
[WebService(Namespace = "http://localhost/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class CombinedSearch : WebService
{
    private DataTable SearchResultsToReturn;
    private SearchType SearchType;
    private Contact ShopperToSearchFor;
    private  DataTable kmsSearchResults;
    private  DataTable crmSearchResults;

    public CombinedSearch()
    {
        SearchResultsToReturn = new DataTable();
        SearchResultsToReturn.Columns.Add("FirstName");
        SearchResultsToReturn.Columns.Add("LastName");
        SearchResultsToReturn.Columns.Add("Email");
        SearchResultsToReturn.Columns.Add("IdNumber");
        SearchResultsToReturn.Columns.Add("SystemIdentifier");
        SearchResultsToReturn.PrimaryKey = new DataColumn[] {SearchResultsToReturn.Columns["SystemIdentifier"]};

        kmsSearchResults = new DataTable();
        kmsSearchResults.Columns.Add("FirstName");
        kmsSearchResults.Columns.Add("LastName");
        kmsSearchResults.Columns.Add("Email");
        kmsSearchResults.Columns.Add("IdNumber");
        kmsSearchResults.Columns.Add("SystemIdentifier");
        kmsSearchResults.PrimaryKey = new DataColumn[] {kmsSearchResults.Columns["SystemIdentifier"] };

        crmSearchResults = new DataTable();
        crmSearchResults.Columns.Add("FirstName");
        crmSearchResults.Columns.Add("LastName");
        crmSearchResults.Columns.Add("Email");
        crmSearchResults.Columns.Add("IdNumber");
        crmSearchResults.Columns.Add("SystemIdentifier");
        crmSearchResults.PrimaryKey=new DataColumn[]{crmSearchResults.Columns["SystemIdentifier"]};

    }

   
    private void SetSearchTypeFromSearchParameters(string searchParameter)
    {
        try
        {
            SearchType = SearchType.FullName;
            if (searchParameter.Contains("@"))
            {
                SearchType = SearchType.EmailAddress;
            }
            else
            {
                Int64 determiningDataTypeOfSearchParameter = 0;
                determiningDataTypeOfSearchParameter = Int64.Parse(searchParameter);

                if (determiningDataTypeOfSearchParameter != 0)
                {
                    if (determiningDataTypeOfSearchParameter.ToString().Length == 13)
                    {
                        SearchType = SearchType.IdNumber;
                    }
                    else
                    {
                        SearchType = SearchType.PhoneNumber;
                    }
                }
            }
            
        }
        catch(FormatException)
        {
            SearchType = SearchType.FullName;
        }
    }

    private void SearchKmsPopulateLocalDatatable()
    {
        SearchResult KmsShoppers = SearchKms(ShopperToSearchFor);
        if(KmsShoppers.Amount>0)
        {
            foreach (Shopper shopper in KmsShoppers.Shoppers)
            {
                DataRow row = kmsSearchResults.NewRow();
                string[] rowArray = new string[] { shopper.FirstName, shopper.LastName, shopper.Email, shopper.IdNumber, shopper.ShopperId };
                row.ItemArray = rowArray;
                kmsSearchResults.Rows.Add(row);
            }
        }
        
    }
    private void SearchCrmPopulateLocalDataTable()
    {
        DataTable searchResultsFromCrm = SearchCrm(ShopperToSearchFor);
        
        foreach (DataRow crmContact in searchResultsFromCrm.Rows)
        {
            DataRow row = crmSearchResults.NewRow();
            string[] crmContactArray = new string[] { crmContact.ItemArray.GetValue(0).ToString(), crmContact.ItemArray.GetValue(1).ToString(), crmContact.ItemArray.GetValue(2).ToString(), crmContact.ItemArray.GetValue(3).ToString(), crmContact.ItemArray.GetValue(4).ToString() };

            row.ItemArray = crmContactArray;
        
            crmSearchResults.Rows.Add(row);
        }
    }

    [WebMethod]
    public DataTable Search(string searchParameter)
    {
            SetSearchTypeFromSearchParameters(searchParameter);
            convertSearchStringToFields(searchParameter);
        SearchCrmPopulateLocalDataTable();
        SearchKmsPopulateLocalDatatable();

        if(crmSearchResults.Rows.Count > 0 )
        {
            foreach (DataRow row in crmSearchResults.Rows)
            {
                DataRow recordToAddInSearchResultsTable = SearchResultsToReturn.NewRow();
                recordToAddInSearchResultsTable.ItemArray = row.ItemArray;
                SearchResultsToReturn.Rows.Add(recordToAddInSearchResultsTable);
            }
        }

        if(kmsSearchResults.Rows.Count>0)
        {
            foreach (DataRow row in kmsSearchResults.Rows)
            {
                bool ContactIsDuplicated = false;
                foreach(DataRow sourceRows in SearchResultsToReturn.Rows)
                {
                    string kmsEmailAddress = row["Email"].ToString().ToLower();
                    string crmEmailAddress = sourceRows["Email"].ToString().ToLower();
                    if(kmsEmailAddress.Equals(crmEmailAddress))
                    {
                        ContactIsDuplicated = true;
                    }
                }

                if(ContactIsDuplicated==false)
                {
                    DataRow recordToAddInSearchResultsTable = SearchResultsToReturn.NewRow();
                    recordToAddInSearchResultsTable.ItemArray = row.ItemArray;
                    SearchResultsToReturn.Rows.Add(recordToAddInSearchResultsTable);
                }
                
            }
        }
        return SearchResultsToReturn;
    }

    

    
   

    /// <summary>
    /// Converts the search string to fields.
    /// This needs to be called before any of the search method's are executed, so that the local fields
    /// can be populated
    /// using the <typeparamref name="searchType"/> TypeOfSearchToPeform type
    /// <list type="bullet">
    /// <item>If it is a _email address, assign's the searchParameterToConvert to EmailAddress</item>
    /// <item>If it contains a space, splits the string using char.Parse(" ") and assign's the first value to first name, and
    /// second value to <paramref name="LastName"/>LastName</item>
    /// <item>If it is none of the above, assign's it to phone number</item>
    /// </list>
    /// When it is a full name search, it takes the string and tries to split it on space's
    /// if there is more than one spaces, the first "Word" will go to first name and all the subsequent words will go to last name.
    /// </summary>
    /// <param name="searchParameterToConvert">The search parameter to convert.</param>
    private void convertSearchStringToFields(string searchParameterToConvert)
    {
        ShopperToSearchFor = new Contact();

        switch (SearchType)
        {
            case SearchType.EmailAddress:
                ShopperToSearchFor.EmailAddress = searchParameterToConvert;
                break;

            case SearchType.FullName:
                string[] NamedSearchParameters = searchParameterToConvert.Split(char.Parse(" "));

                if (NamedSearchParameters.Length > 2)
                {
                    ShopperToSearchFor.FirstName = NamedSearchParameters.GetValue(0).ToString();

                    for (int i = 1; NamedSearchParameters.Length > i; ++i)
                    {
                        ShopperToSearchFor.LastName = ShopperToSearchFor.LastName + " " +
                                                      NamedSearchParameters.GetValue(i).ToString();
                    }
                }
                else
                {
                    ShopperToSearchFor.FirstName = NamedSearchParameters.GetValue(0).ToString();
                    if (NamedSearchParameters.Length > 1)
                    {
                        ShopperToSearchFor.LastName = NamedSearchParameters.GetValue(1).ToString();
                    }
                }
                break;

            case SearchType.PhoneNumber:
                ShopperToSearchFor.MobileNumber = searchParameterToConvert;
                ShopperToSearchFor.PhoneNumber = searchParameterToConvert;
                break;

            case SearchType.ShopperId:
                ShopperToSearchFor.ShopperId = searchParameterToConvert;
                break;
        }
    }

    /// <summary>
    /// Fetches the parameters.
    /// </summary>
    /// <param name="ContactToCreateFetchParametersFrom">The contact to create fetch parameters from.</param>
    /// <returns></returns>
    private string FetchParameters(Contact ContactToCreateFetchParametersFrom)
    {
        StringBuilder fetchParameters = new StringBuilder();

        switch (SearchType)
        {
            case SearchType.FullName:
                fetchParameters.AppendFormat(Resources.FullNameSearchParameter,
                                             ContactToCreateFetchParametersFrom.FirstName,
                                             ContactToCreateFetchParametersFrom.LastName);
                break;
            case SearchType.EmailAddress:
                fetchParameters.AppendFormat(Resources.EmailSearchParameter,
                                             ContactToCreateFetchParametersFrom.EmailAddress);
                break;
            case SearchType.IdNumber:
                fetchParameters.AppendFormat(Resources.IdNumberSearchParameter,
                                             ContactToCreateFetchParametersFrom.PersonIdNumber);
                break;
            case SearchType.PhoneNumber:
                fetchParameters.AppendFormat(Resources.TelephoneNumberSearchParameter,
                                             ContactToCreateFetchParametersFrom.PhoneNumber);
                break;
        }

        return fetchParameters.ToString();
    }

    /// <summary>
    /// Searches crm,using fetch statements that is included in the resources file
    /// </summary>
    /// <param name="ContactToSearchFor">The contact to search for</param>
    /// <returns>Returns null, if no records are found</returns>
    private DataTable SearchCrm(Contact ContactToSearchFor)
    {
        StringBuilder xmlFetch = new StringBuilder();
        xmlFetch.AppendFormat(Resources.XmlFetchSearchContacts, FetchParameters(ContactToSearchFor));

        // Fetch the results.
        String results;
        try
        {
            CrmService localService = Common.CrmWebServiceProxy();
            results = localService.Fetch(xmlFetch.ToString());
        }

        catch (SoapException soapException)
        {
            results = soapException.Detail.InnerXml;
            Common.LogErrorMessage(soapException);
        }
        catch (Exception error)
        {
            results = error.Message;
            Common.LogErrorMessage(error);
        }
        if (results != Resources.NoResults)
        {
            return ConvertIntoDataTable(results);
        }
        else
        {
            DataTable emptyTable = new DataTable();
            return emptyTable;
        }
    }

    /// <summary>
    /// Converts the crm results tring into tabledata .
    /// </summary>
    /// <param name="CrmFetchResultsString">The CRM fetch results string.</param>
    /// <returns>the result table</returns>
    private static DataTable ConvertIntoDataTable(string CrmFetchResultsString)
    {
        DataSet ds = new DataSet();
        DataTable dataTable = new DataTable();
        StringReader reader = new StringReader(CrmFetchResultsString);
        ds.ReadXml(reader);
        return ds.Tables["result"];
    }

    /// <summary>
    /// Searches the KMS.
    /// by calling the SearchShoppers web services
    /// then creating the authorization header, using username and password that is
    /// specified in the resources file
    /// </summary>
    /// <returns>No restrictions on the amount of shoppers that it searches on</returns>
    private static SearchResult SearchKms(Contact shopperToSearchFor)
    {
        CRMService kmsSearchService = Common.KalahariManagmentSystemWebServiceProxy();

        SearchResult result = kmsSearchService.SearchShoppers
            (shopperToSearchFor.FirstName
             , shopperToSearchFor.LastName
             , shopperToSearchFor.PhoneNumber
             , shopperToSearchFor.MobileNumber
             , shopperToSearchFor.EmailAddress
             , shopperToSearchFor.ShopperId
             , shopperToSearchFor.OrderNumber
            );
        return result;
    }
}
